package de.tu_darmstadt.gdi.battleship;

import java.awt.print.Printable;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;

import javax.activity.InvalidActivityException;
import javax.sound.midi.InvalidMidiDataException;

/**
 * 
 * @author Marcel Andreas Gazsi
 * 
 */
public class Map {
	//TODO: Kein Schiff direkt an ein anderes
	private char[][] map;
	private char[][] fieldForPlayer1;
	private char[][] fieldForPlayer2;

	/**
	 * Standard constructor for the class.
	 * 
	 * @param pathToFile
	 *            String The path to the .lvl which should be read.
	 * @throws InvalidMapException 
	 */
	public Map(String pathToFile) throws InvalidMapException {
		FileReader fr;
		try {
			fr = new FileReader(pathToFile);
			BufferedReader br = new BufferedReader(fr);
			String row = null;
			map = new char[21][10];
			fieldForPlayer1 = new char[10][10];
			fieldForPlayer2 = new char[10][10];
			// Wird genutzt um die zweite Dimension des Arrays anzusprechen.
			int iterator = 0;

			// Zeilenweise die Datei auslesen.
			try {
				while ((row = br.readLine()) != null) {
					// Durch dieses Hilfgerüst kann ich Zeilenweise durch den
					// String gehen und mir die Chars ansehen.
					for(int i = 0; i < row.length(); i++){
						char temp = row.charAt(i);
						map[i][iterator] = temp;
						if(i > 10)
							fieldForPlayer2[i-11][iterator] = temp;
						else if(i < 10)
							fieldForPlayer1[i][iterator] = temp;
						
					}
					iterator++;
				}
				isValide();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	}

	/**
	 * This function checks for both fields if the players had set all ships
	 * 
	 * @return True or Fals Whether all ships had benn set or not.
	 * @throws InvalidMapException
	 */
	public boolean isValide() throws InvalidMapException {
		if (checkIfPlayerHasSetAllBoats(fieldForPlayer1)
				&& checkIfPlayerHasSetAllBoats(fieldForPlayer2))
			return true;
		else
			throw new InvalidMapException(
					"Es wurde nicht die korrekte Anzahl von Schiffen gefunden!");
	}

	/**
	 * This function checks if the given map field part of the map contains the
	 * correct number of ships.
	 * 
	 * @param field
	 *            Char[][] Two dimensional char Array which represents a field
	 *            for a player.
	 * @return Boolean True or false whether the map is correct or not.
	 * @throws InvalidMapException
	 */
	private boolean checkIfPlayerHasSetAllBoats(char[][] field)
			throws InvalidMapException {
		int countSpeedboats = 0;
		int countDestroyer = 0;
		int countCruiser = 0;
		int countBattleship = 0;

		for (int i = 0; i < 10; i++) {
			// Prüfe das erste Feld ob es ein Schiff ist und wenn ja ob es
			// horizontal oder vertikal liegt.
			for (int j = 0; j < 10; j++) {
				// Hier wird geprüft um welche Art von Schiff es sich handel, in
				// dem wir die darauf folgenden Felder prüfen.
				if (Character.toLowerCase(field[j][i]) == 'l') {
					if (Character.toLowerCase(field[j+1][i]) == 'r')
						countSpeedboats++;
					else if (Character.toLowerCase(field[j+1][i]) == 'h' && Character.toLowerCase(field[j+2][i]) == 'r')
						countDestroyer++;
					else if (Character.toLowerCase(field[j+1][i]) == 'h' && Character.toLowerCase(field[j+2][i]) == 'h' && Character.toLowerCase(field[j+3][i]) == 'r')
						countCruiser++;
					else if (Character.toLowerCase(field[j+1][i]) == 'h' && Character.toLowerCase(field[j+2][i]) == 'h' && Character.toLowerCase(field[j+3][i]) == 'h' && Character.toLowerCase(field[j+4][i]) == 'r')
						countBattleship++;
					// Hier geschieht das Gleiche wie oben nur prüfen wir dieses
					// mal vertikal.
				} else if (Character.toLowerCase(field[j][i]) == 't') {
					if (Character.toLowerCase(field[j][i+1]) == 'b')
						countSpeedboats++;
					else if (Character.toLowerCase(field[j][i+1]) == 'v' && Character.toLowerCase(field[j][i+2]) == 'b')
						countDestroyer++;
					else if (Character.toLowerCase(field[j][i+1]) == 'v' && Character.toLowerCase(field[j][i+2]) == 'v' && Character.toLowerCase(field[j][i+3]) == 'b')
						countCruiser++;
					else if (Character.toLowerCase(field[j][i+1]) == 'v' && Character.toLowerCase(field[j][i+2]) == 'v' && Character.toLowerCase(field[j][i+3]) == 'v' && Character.toLowerCase(field[j][i+4]) == 'b')
						countBattleship++;
				}
				
				// Hier wird auf fehlerhafte Kombinationen geprüft.
				// TODO: Hier auf Arraygrenzen prüfen.
				if((Character.toLowerCase(field[i][j])) == 'l')
					if(i+1 < 8 && (Character.toLowerCase(field[i+1][j]) == 'l'))
						throw new InvalidMapException("Es wurde ein Fehler im Level gefunden!");
				if((Character.toLowerCase(field[i][j])) == 'r')
					if(i+1 < 8 && Character.toLowerCase(field[i+1][j]) == 'r')
						throw new InvalidMapException("Es wurde ein Fehler im Level gefunden!");
				if((Character.toLowerCase(field[i][j])) == 't')
					if(j+1 < 8 && Character.toLowerCase(field[i][j+1]) == 't')
						throw new InvalidMapException("Es wurde ein Fehler im Level gefunden!");
				if((Character.toLowerCase(field[i][j])) == 'b')
					if(j+1 < 8 && (Character.toLowerCase(field[i][j+1]) == 'b'))
					throw new InvalidMapException("Es wurde ein Fehler im Level gefunden!");
						
			}
		}
		if (countSpeedboats != 4 || countDestroyer != 3 || countCruiser != 2
				|| countBattleship != 1) {
			throw new InvalidMapException(
					"Es wurde nicht die korrekte Anzahl von Schiffen gefunden!");
		} else
			return true;
	}
	
	/**
	 * Overwrites the field of player1
	 * 
	 * @param newField Char[][] The new field for player1
	 * @throws InvalidMapException
	 */
	public void setFieldForPlayer1(char[][] newField) throws InvalidMapException{
		if(checkIfPlayerHasSetAllBoats(newField))
			fieldForPlayer1 = newField;
	}
	
	/**
	 * Returns the field of player1
	 * 
	 * @return Char[][] The field of player1
	 */
	public char[][] getFieldForPlayer1(){
		return fieldForPlayer1;
	}
	
	/**
	 * Overwrites the field of player2 with the given.
	 * 
	 * @param newField Char[][] The new field for player2
	 * @throws InvalidMapException 
	 */
	public void setFieldForPlayer2(char[][] newField) throws InvalidMapException{
		if(checkIfPlayerHasSetAllBoats(newField))
			fieldForPlayer2 = newField;
	}
	
	/**
	 * Returns the field of player2
	 * 
	 * @return char[][] The field of player2
	 */
	public char[][] getFieldForPlayer2(){
		return fieldForPlayer2;	
	}
	/**
	 * to set a working-map as map
	 * @param newMap
	 */
	public void setWholeMap(char[][] newMap){
		this.map = newMap;
	}
	
	public char[][] returnWholeMap(){
		return this.map;
	}
}
